﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using ShredTheLog.Model;
using System.Diagnostics.Contracts;
using System.Windows.Threading;
using System.Windows;
using ShredTheLog.Common.MVVM;
using ShredTheLog.Api.DataContracts;
using ShredTheLog.Api;
using System.ComponentModel.Composition;
using System.Windows.Data;

namespace ShredTheLog.ViewModels
{
    public sealed class LogInViewModel : ViewModelBase
    {
        [Import]
        private IShredServices ShredServices { get; set; }

        [Import]
        private IConnectionSettingsSection ConnectionSettings { get; set; }

        [Import]
        private ILoginNotificationSource LoginNotificationSource { get; set; }

        private readonly Action<ISessionCredentials> _onLogin;

        public LogInViewModel(Action<ISessionCredentials> onLogin)
        {
            Contract.Requires(onLogin != null);

            _onLogin = onLogin;
            InitialUserName = ConnectionSettings.UserName;
            InitialPassword = ConnectionSettings.Password;
            InitialRememberPassword = !String.IsNullOrEmpty(InitialPassword);

            // TODO: Нужно выделять имя пользователя при открытии окна
            //usernameBox.SelectAll();
            //usernameBox.Focus();
        }

        public string InitialUserName { get; private set; }
        public string InitialPassword { get; private set; }
        public bool InitialRememberPassword { get; private set; }

        public bool IsWindowClosed
        {
            get { return _isWindowClosed; }
            set { _isWindowClosed = value; OnPropertyChanged(() => IsWindowClosed); }
        }
        private bool _isWindowClosed;

        public bool IsLoggingIn
        {
            get { return _isLoggingIn; }
            set { _isLoggingIn = value; OnPropertyChanged(() => IsLoggingIn); }
        }
        private bool _isLoggingIn;

        private ICommand _logInCommand;
        public ICommand LogInCommand
        {
            get
            {
                if (_logInCommand == null)
                {
                    Action<LogInCommandParameter> action =
                        p =>
                        {
                            if (p == null || string.IsNullOrEmpty(p.UserName) || String.IsNullOrEmpty(p.Password) || IsLoggingIn) return;

                            IsLoggingIn = true;
                            ConnectionSettings.GetClient().LogIn(p.UserName, p.Password).ObserveOn(ShredServices.Dispatcher).Subscribe(
                                sessionCredentials =>
                                {
                                    Contract.Requires(sessionCredentials != null);

                                    try
                                    {
                                        _onLogin(sessionCredentials);
                                        LoginNotificationSource.OnNext(sessionCredentials);
                                        ConnectionSettings.UserName = p.UserName;
                                        if (p.RememberPassword)
                                            ConnectionSettings.Password = p.Password;
                                        else
                                            ConnectionSettings.Password = null;

                                        ShredServices.SaveSettings(false);
                                        IsWindowClosed = true;
                                    }
                                    catch (Exception ex)
                                    {
                                        ShredServices.ShowError(ex);
                                    }
                                    finally
                                    {
                                        IsLoggingIn = false;
                                    }
                                },
                                ex =>
                                {
                                    IsLoggingIn = false;
                                    if (ex is LoginException)
                                    {
                                        if (ex is InvalidCredentialsException)
                                            ShredServices.ShowError(() => ShredServices.GetLocalizedString("s_InvalidCredentialsException"), ex);
                                        else if (ex is UserDeletedException)
                                            ShredServices.ShowError(() => ShredServices.GetLocalizedString("s_UserDeletedException"), ex);
                                        else if (ex is FullBanException)
                                            ShredServices.ShowError(() => ShredServices.GetLocalizedString("s_FullBanException"), ex);
                                        else
                                            ShredServices.ShowError(() => ShredServices.GetLocalizedString("s_LoginException"), ex);
                                    }
                                    else
                                    {
                                        ShredServices.ShowError(ex);
                                    }
                                });
                        };
                    _logInCommand = new DelegateCommand<LogInCommandParameter>(action, p => p != null && !String.IsNullOrWhiteSpace(p.UserName) && !String.IsNullOrEmpty(p.Password) && !IsLoggingIn);
                }
                return _logInCommand;
            }
        }

        private ICommand _closeCommand;
        public ICommand CloseCommand
        {
            get
            {
                if (_closeCommand == null)
                {
                    _closeCommand = new DelegateCommand(() => { IsWindowClosed = true; });
                }
                return _closeCommand;
            }
        }
    }

    public sealed class LogInCommandParameter
    {
        public string UserName { get; private set; }
        public string Password { get; private set; }
        public bool RememberPassword { get; private set; }

        public LogInCommandParameter(string userName, string password, bool rememberPassword)
        {
            UserName = userName;
            Password = password;
            RememberPassword = rememberPassword;
        }
    }

    public sealed class LogInCommandParameterConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Contract.Assume(values.Length == 3);

            var userName = values[0] as string;
            var password = values[1] as string;
            var rememberPassword = (bool)values[2];

            if (!String.IsNullOrEmpty(userName) && !String.IsNullOrEmpty(password))
                return new LogInCommandParameter(userName, password, rememberPassword);
            else
                return null;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException();
        }

        public static readonly LogInCommandParameterConverter Default = new LogInCommandParameterConverter();
    }
}
